﻿using AutoUpdateTools.Models;
using MessageServer.Update;
using Rebex.IO.Compression;
using System;
using System.Data.SqlClient;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;

namespace AutoUpdateTools.Update
{
    /// <summary>
    /// 更新基类
    /// </summary>
    public interface IUpdateInterface
    {

        /// <summary>
        /// 获取版本号
        /// </summary>
        /// <returns></returns>
        string GetVersion(); 
        /// <summary>
        /// 执行备份
        /// </summary>
        bool ExecBak(string downloadFileName,PackageSetupInfoEntity packageSetupInfo);


        /// <summary>
        /// 执行更新
        /// </summary>
        bool ExecUpdate();

        /// <summary>
        /// 执行回滚的操作
        /// </summary>
        bool ExecRollBack();

             
    }
    /// <summary>
    /// sql更新处理类
    /// </summary>
    public class DBUpdateClass : IUpdateInterface
    {
        private PackageAllInfo packageAllInfo = null;
        private PackageSetupInfoEntity packageSetupInfo = null;

        private string sqkBakFile = "";
            
        public DBUpdateClass(PackageAllInfo packageAllInfo )
        {
            this.packageAllInfo = packageAllInfo;
            sqlCon = new SqlConnection(packageAllInfo.LocalFilePath);
        }
        ~DBUpdateClass()
        {
            sqlCon.Close();
            sqlCon.Dispose();
        }
        SqlConnection sqlCon = null;
        string updatePackagePath = "";
        string bakPath = "";
        public bool ExecBak(string downloadFileName, PackageSetupInfoEntity packageSetupInfo)
        {
            sqkBakFile = "";
            this.packageSetupInfo = packageSetupInfo;

            //重新设置一个新的更新包文件的路径 
            updatePackagePath = Path.Combine(Path.GetDirectoryName(downloadFileName), DateTime.Now.ToString("yyyyMMddHHmmss"));
            if (System.IO.Directory.Exists(updatePackagePath) == false)
            {
                System.IO.Directory.CreateDirectory(updatePackagePath);
            }

            if (packageSetupInfo.IsZip == true)  //解压到这个新的文件夹当中
            {
                //进行解压的处理
                RebexRegister.Register();
                using (ZipArchive archive = new ZipArchive(downloadFileName))
                {
                    ArchiveOperationResult result = archive.ExtractAll(updatePackagePath);
                }
            }
            else // 把下载的单个文件复制到新的文件夹当中
            {
                System.IO.File.Move(downloadFileName, System.IO.Path.Combine(updatePackagePath, Path.GetFileName(downloadFileName)));
            }
            var bakPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bak");

            if (System.IO.Directory.Exists(bakPath) == false)
            {
                System.IO.Directory.Delete(bakPath, true);
                System.IO.Directory.CreateDirectory(bakPath);
            }
            //执行更新操作
            //执行备份 
            string sqlbakfile = ""; //数据库备份的文件  

            sqkBakFile = System.IO.Path.Combine(bakPath, "database", $"{DateTime.Now.ToString("yyyyMMdd")}.bak");
            if (System.IO.File.Exists(sqlbakfile))
            {
                System.IO.File.Delete(sqlbakfile);
            }
            SqlConnectionStringBuilder constringObj = new SqlConnectionStringBuilder(packageAllInfo.LocalFilePath);
            string backupDbString = $"BACKUP DATABASE {constringObj.InitialCatalog} TO DISK = '{sqlbakfile}' WITH FORMAT;";

            SqlCommand cmd = new SqlCommand(backupDbString, sqlCon);
            cmd.ExecuteNonQuery(); 
            return System.IO.File.Exists(sqlbakfile);
        }

        public bool ExecRollBack()
        {
            //执行数据库还原
            FileBak.递归复制文件(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "dbbak"), bakPath);

            SqlConnectionStringBuilder constringObj = new SqlConnectionStringBuilder(packageAllInfo.LocalFilePath);
            using (SqlConnection con = new SqlConnection(packageAllInfo.LocalFilePath))
            {
                string cmdText = $"restore database {constringObj.InitialCatalog} from disk='{sqkBakFile}'";
                SqlCommand cmd = new SqlCommand(cmdText, con);
                cmd.ExecuteNonQuery();
                return true;
            }
        }

        public bool ExecUpdate()
        {
            SqlCommand cmd = new SqlCommand();
            cmd.Connection = sqlCon;

            foreach (string filename in System.IO.Directory.GetFiles(updatePackagePath).OrderBy(n => n))
            {
                using (StreamReader sr = new StreamReader(filename))
                {
                    string content = sr.ReadToEnd();
                    cmd.CommandText = content;
                    cmd.ExecuteNonQuery();
                }
            }
            //更新数据库的版本号
            string updateVersionSql = $"update {packageAllInfo.UpdatePath} set {packageAllInfo.CheckVersionFile}={packageSetupInfo.Version}";
            cmd.CommandText = updateVersionSql;
            cmd.ExecuteNonQuery();

            //删除备份的文件和删除更新的文件
            System.IO.Directory.Delete(bakPath, true);
            System.IO.Directory.Delete(updatePackagePath, true);
            return true;
        }

        public string GetVersion()
        {
            string version = "";
            string cmdVersionSql = string.Format("select {0} from {1}", packageAllInfo.CheckVersionFile, packageAllInfo.UpdatePath);
            SqlCommand cmd = new SqlCommand(cmdVersionSql, sqlCon);
            version = cmd.ExecuteScalar().ToString();
            return version;
        }
    }


    public class WebUpdateClass:IUpdateInterface
    {
        private PackageAllInfo packageAllInfo = null;
        PackageSetupInfoEntity packageSetupInfo =null;

        public WebUpdateClass(PackageAllInfo packageAllInfo)
        {
            this.packageAllInfo = packageAllInfo;
        }
        string updatePackagePath = ""; 
        string bakPath = "";
        public bool ExecBak(string downloadFileName, PackageSetupInfoEntity packageSetupInfo)
        { 
            this.packageSetupInfo = packageSetupInfo;

            //重新设置一个新的更新包文件的路径 
            updatePackagePath = Path.Combine(Path.GetDirectoryName(downloadFileName), DateTime.Now.ToString("yyyyMMddHHmmss"));
            if (System.IO.Directory.Exists(updatePackagePath) == false)
            {
                System.IO.Directory.CreateDirectory(updatePackagePath);
            }

            if (packageSetupInfo.IsZip == true)  //解压到这个新的文件夹当中
            {
                //进行解压的处理
                RebexRegister.Register();
                using (ZipArchive archive = new ZipArchive(downloadFileName))
                {
                    ArchiveOperationResult result = archive.ExtractAll(updatePackagePath);
                }
            }
            else // 把下载的单个文件复制到新的文件夹当中
            {
                System.IO.File.Move(downloadFileName, System.IO.Path.Combine(updatePackagePath, Path.GetFileName(downloadFileName)));
            }
            var bakPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bak");

            if (System.IO.Directory.Exists(bakPath) == false)
            {
                System.IO.Directory.Delete(bakPath, true);
                System.IO.Directory.CreateDirectory(bakPath);
            }
            //先执行备份
            FileBak.递归备份文件(bakPath,packageAllInfo.LocalFilePath, updatePackagePath);
          
            return true;
        }

        public bool ExecRollBack()
        {
            FileBak.递归复制文件(packageAllInfo.LocalFilePath, bakPath);

            System.IO.Directory.Delete(bakPath, true);
            //删除获取的更新文件和更新文件 
            System.IO.Directory.Delete(updatePackagePath, true);
            return true;
        }

        public bool ExecUpdate()
        {
            //文件进行替换
            FileBak.递归复制文件(packageAllInfo.LocalFilePath, updatePackagePath);
            return true;

        }

        public string GetVersion()
        {
            string version = "";
            string localFile = packageAllInfo.LocalFilePath + packageAllInfo.CheckVersionFile.Replace("/", @"\");
            if (File.Exists(localFile))
            {
                var ass = Assembly.Load(localFile);
                version = ass.GetName().Version.ToString();
            }
            return version;
        }
    }


    public class ExeUpdateClass : IUpdateInterface
    {
        private PackageAllInfo packageAllInfo = null;
        PackageSetupInfoEntity packageSetupInfo = null;

        public ExeUpdateClass(PackageAllInfo packageAllInfo)
        {
            this.packageAllInfo = packageAllInfo;
        }

        string updatePackagePath = "";
        string bakPath = "";
        bool isExecute = false; //判断exe是否正在执行
        public bool ExecBak(string downloadFileName, PackageSetupInfoEntity packageSetupInfo)
        {
            this.packageSetupInfo = packageSetupInfo;
            //重新设置一个新的更新包文件的路径 
            updatePackagePath = Path.Combine(Path.GetDirectoryName(downloadFileName), DateTime.Now.ToString("yyyyMMddHHmmss"));
            if (System.IO.Directory.Exists(updatePackagePath) == false)
            {
                System.IO.Directory.CreateDirectory(updatePackagePath);
            }

            if (packageSetupInfo.IsZip == true)  //解压到这个新的文件夹当中
            {
                //进行解压的处理
                RebexRegister.Register();
                using (ZipArchive archive = new ZipArchive(downloadFileName))
                {
                    ArchiveOperationResult result = archive.ExtractAll(updatePackagePath);
                }
            }
            else // 把下载的单个文件复制到新的文件夹当中
            {
                System.IO.File.Move(downloadFileName, System.IO.Path.Combine(updatePackagePath, Path.GetFileName(downloadFileName)));
            }
            var bakPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bak");

            if (System.IO.Directory.Exists(bakPath) == false)
            {
                System.IO.Directory.Delete(bakPath, true);
                System.IO.Directory.CreateDirectory(bakPath);
            }
            //检查程序是正在执行,如果在执行则停止,
            string exeFileName = Path.GetFileName(packageAllInfo.CheckVersionFile).ToLower();

            //判断进程中是否存在次
            var lstProc = Process.GetProcesses().Where(n => n.ProcessName.ToLower().StartsWith(exeFileName)).ToList();
            isExecute = lstProc.Count > 0;
            foreach (var proc in lstProc)
            {
                proc.Kill();
            }
            //先执行备份
            FileBak.递归备份文件(bakPath, packageAllInfo.LocalFilePath, updatePackagePath);

            return true;
        }

        public bool ExecRollBack()
        {
            FileBak.递归复制文件(packageAllInfo.LocalFilePath, bakPath);
            System.IO.Directory.Delete(bakPath, true);
            //删除获取的更新文件和更新文件 
            System.IO.Directory.Delete(updatePackagePath, true);
            ExecExe();
            return true;
        }

        public bool ExecUpdate()
        {
            FileBak.递归复制文件(packageAllInfo.LocalFilePath, updatePackagePath);
            ExecExe();
            return true;
        }

        public string GetVersion()
        {
            string version = "";
            string localFile = packageAllInfo.LocalFilePath + packageAllInfo.CheckVersionFile.Replace("/", @"\");
            if (File.Exists(localFile))
            {
                var ass = Assembly.Load(localFile);
                version = ass.GetName().Version.ToString();
            }
            return version;
        } 

        private void ExecExe()
        {
            if (isExecute)
            {
                string exepath = Path.Combine(packageAllInfo.LocalFilePath, packageAllInfo.CheckVersionFile);
                Process.Start(exepath);
            }
        }


    }

    public class FileBak
    {

        /// <summary>
        /// 递归备份文件:两个参数反过来递归还原文件
        /// </summary>
        /// <param name="descPath"></param>
        /// <param name="srcPath"></param>
        public static void 递归复制文件(string descPath, string srcPath)
        {
            if (System.IO.Directory.Exists(descPath) == false)
            {
                System.IO.Directory.CreateDirectory(descPath);
            }
            foreach (var item in System.IO.Directory.GetFiles(srcPath))
            {
                System.IO.File.Copy(item, Path.Combine(descPath, Path.GetFileName(item)), true);
            }
            foreach (var item in System.IO.Directory.EnumerateDirectories(srcPath))
            {
                递归复制文件(Path.Combine(descPath, Path.GetFileName(item)), item);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="descPath"></param>
        /// <param name="srcPath"></param>
        public static void 递归备份文件(string 备份目录, string 原始目录, string 参考目录)
        {
            foreach (var item in System.IO.Directory.GetFiles(参考目录))
            {
                string descFile = item.Replace(参考目录, 备份目录);
                string srcFile = item.Replace(参考目录, 原始目录);
                if (System.IO.Directory.Exists(Path.GetDirectoryName(descFile)) == false)
                {
                    System.IO.Directory.CreateDirectory(Path.GetDirectoryName(descFile));
                }
                System.IO.File.Copy(srcFile, descFile, true);
            }
        }
    }
}
